package org.springblade.common.utils;

import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 慢SQL记录工具类 - 基于JdbcTemplate重构版本
 * 支持多环境配置和Spring管理的数据库连接
 *
 * @author: sharry, Jackey
 * @since: 2023-10-16
 */
@Component
@Slf4j
public class JdbcUtils implements ApplicationContextAware {

	private static ApplicationContext applicationContext;
	private static JdbcTemplate jdbcTemplate;
	private static DruidDataSource dataSource;

	// 配置参数（支持环境变量覆盖）
	private static String dbUrl;
	private static String dbUsername;
	private static String dbPassword;
	private static boolean enabled = true;

	@Override
	public void setApplicationContext(ApplicationContext context) {
		applicationContext = context;
	}

	@PostConstruct
	public void init() {
		initializeDataSourceAndTemplate();
	}

	/**
	 * 初始化数据源和JdbcTemplate
	 */
	private static void initializeDataSourceAndTemplate() {
		try {
			// 从环境变量或系统属性读取配置
			loadConfiguration();

			if (!enabled) {
				log.info("慢SQL记录功能已禁用");
				return;
			}

			// 创建数据源
			dataSource = new DruidDataSource();
			dataSource.setUrl(dbUrl);
			dataSource.setUsername(dbUsername);
			dataSource.setPassword(dbPassword);
			dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
			dataSource.setInitialSize(3);
			dataSource.setMaxActive(5);
			dataSource.setMaxWait(30000L);

			// 设置验证查询
			dataSource.setValidationQuery("select 1");
			dataSource.setTestWhileIdle(true);
			dataSource.setTestOnBorrow(false);
			dataSource.setTestOnReturn(false);

			// 创建JdbcTemplate
			jdbcTemplate = new JdbcTemplate(dataSource);

			log.info("慢SQL JdbcTemplate初始化成功，数据库URL: {}", maskUrl(dbUrl));

		} catch (Exception e) {
			log.error("初始化慢SQL JdbcTemplate失败，使用默认配置", e);
			initDefaultDataSourceAndTemplate();
		}
	}

	/**
	 * 加载配置（支持环境变量和Spring Profile）
	 */
	private static void loadConfiguration() {
		// 检查环境变量
		String envEnabled = System.getenv("SLOW_SQL_ENABLED");
		String envUrl = System.getenv("SLOW_SQL_DB_URL");
		String envUsername = System.getenv("SLOW_SQL_DB_USERNAME");
		String envPassword = System.getenv("SLOW_SQL_DB_PASSWORD");

		// 检查系统属性
		String propEnabled = System.getProperty("slow.sql.enabled");
		String propUrl = System.getProperty("slow.sql.db.url");
		String propUsername = System.getProperty("slow.sql.db.username");
		String propPassword = System.getProperty("slow.sql.db.password");

		// 检查Spring Profile
		String activeProfile = System.getProperty("spring.profiles.active");
		if (activeProfile == null) {
			activeProfile = System.getenv("SPRING_PROFILES_ACTIVE");
		}

		// 设置enabled状态
		if (envEnabled != null) {
			enabled = Boolean.parseBoolean(envEnabled);
		} else if (propEnabled != null) {
			enabled = Boolean.parseBoolean(propEnabled);
		}

		// 设置数据库配置
		if (envUrl != null) {
			dbUrl = envUrl;
			dbUsername = envUsername != null ? envUsername : "root";
			dbPassword = envPassword != null ? envPassword : "Erised2021!";
		} else if (propUrl != null) {
			dbUrl = propUrl;
			dbUsername = propUsername != null ? propUsername : "root";
			dbPassword = propPassword != null ? propPassword : "Erised2021!";
		} else {
			// 根据Spring Profile设置默认配置
			if ("dev".equals(activeProfile)) {
				dbUrl = "jdbc:mysql://221.4.198.163:3304/sida_maintain?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true";
			} else if ("test".equals(activeProfile)) {
				dbUrl = "jdbc:mysql://10.15.36.5:3306/sida_maintain?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true";
			} else {
				dbUrl = "jdbc:mysql://221.4.198.163:3306/sida_maintain?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true";
			}
			dbUsername = "root";
			dbPassword = "Erised2021!";
		}

		log.info("慢SQL配置加载完成 - 启用状态: {}, Profile: {}, URL: {}", enabled, activeProfile, maskUrl(dbUrl));
	}

	/**
	 * 初始化默认数据源和JdbcTemplate（向后兼容）
	 */
	private static void initDefaultDataSourceAndTemplate() {
		dataSource = new DruidDataSource();
		dataSource.setUrl("jdbc:mysql://221.4.198.163:3306/sida_maintain?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true");
		dataSource.setUsername("root");
		dataSource.setPassword("Erised2021!");
		dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		dataSource.setInitialSize(3);
		dataSource.setMaxActive(5);
		dataSource.setMaxWait(30000);
		dataSource.setValidationQuery("select 1");

		jdbcTemplate = new JdbcTemplate(dataSource);
		log.warn("使用默认慢SQL数据库配置");
	}

	/**
	 * 获取JdbcTemplate实例，如果未初始化则进行初始化
	 */
	private static JdbcTemplate getJdbcTemplate() {
		if (jdbcTemplate == null) {
			synchronized (JdbcUtils.class) {
				if (jdbcTemplate == null) {
					initializeDataSourceAndTemplate();
				}
			}
		}
		return jdbcTemplate;
	}

	/**
	 * 屏蔽URL中的敏感信息用于日志输出
	 */
	private static String maskUrl(String url) {
		if (url == null) {
			return "未配置";
		}
		return url.replaceAll("password=[^&]*", "password=***");
	}

	/**
	 * 将慢SQL告警信息记录到数据库（新版本 - 使用JdbcTemplate）
	 *
	 * @param environment    环境信息
	 * @param executionTime  执行时间（毫秒）
	 * @param apiPath        接口路径
	 * @param sqlStatement   SQL语句
	 */
	public static void insertSlowSqlAlert(String environment, Long executionTime,
										  String apiPath, String sqlStatement) {
		// 检查功能是否启用
		if (!enabled) {
			log.debug("慢SQL记录功能已禁用，跳过记录");
			return;
		}

		try {
			// 生成SQL指纹用于重复检查
			String sqlFingerprint = getSqlFingerprint(sqlStatement);

			if (!isDuplicationInNewTable(sqlFingerprint)) {
				JdbcTemplate template = getJdbcTemplate();
				if (template == null) {
					log.error("无法获取JdbcTemplate，跳过记录");
					return;
				}

				// 构建插入SQL
				String insertSql = "INSERT INTO blade_slow_sql_alert " +
					"(id, environment, execution_time, api_path, sql_statement, alert_time) " +
					"VALUES (?, ?, ?, ?, ?, ?)";

				// 生成ID和时间
				long id = System.currentTimeMillis() * 1000 + (long)(Math.random() * 1000);
				Date now = new Date();

				// 清理和提取纯净的API路径
				String cleanApiPath = extractCleanApiPath(apiPath);

				int result = template.update(insertSql,
					id, environment, executionTime, cleanApiPath, sqlStatement, new Timestamp(now.getTime()));

				log.info("慢SQL告警记录是否成功: {}, 执行时间: {}ms, 接口路径: {}",
					result > 0, executionTime, apiPath);
			} else {
				log.debug("该慢SQL已被记录，跳过重复记录");
			}
		} catch (DataAccessException e) {
			log.error("记录慢SQL告警异常", e);
		}
	}

	/**
	 * 将SQL指纹和执行时间记录到数据库（兼容旧版本 - 使用JdbcTemplate）
	 *
	 * @param sqlFingerprint SQL指纹
	 * @param time           执行时间（毫秒）
	 */
	public static void executeQueryAndInsert(String sqlFingerprint, Long time) {
		try {
			if (!isDuplication(sqlFingerprint)) {
				JdbcTemplate template = getJdbcTemplate();
				if (template == null) {
					log.error("无法获取JdbcTemplate，跳过记录");
					return;
				}

				String insertSql = "INSERT INTO filter_log (time, ip) VALUES (?, ?)";
				int result = template.update(insertSql, time, sqlFingerprint);

				log.info("慢SQL记录是否成功: {}, SQL指纹: {}, 执行时间: {}ms",
					result > 0, sqlFingerprint, time);
			}
		} catch (DataAccessException e) {
			log.error("记录慢SQL异常", e);
		}
	}

	/**
	 * 判断SQL指纹是否已存在（旧表 - 使用JdbcTemplate）
	 *
	 * @param sqlFingerprint SQL指纹
	 * @return 是否已存在
	 */
	public static boolean isDuplication(String sqlFingerprint) {
		try {
			JdbcTemplate template = getJdbcTemplate();
			if (template == null) {
				log.error("无法获取JdbcTemplate");
				return false;
			}

			String sql = "SELECT COUNT(*) FROM filter_log WHERE ip = ?";
			Integer count = template.queryForObject(sql, Integer.class, sqlFingerprint);
			return count != null && count > 0;

		} catch (DataAccessException e) {
			log.error("查询SQL指纹异常", e);
			return false;
		}
	}

	/**
	 * 检查新表中是否存在重复的SQL指纹（使用JdbcTemplate）
	 *
	 * @param sqlFingerprint SQL指纹
	 * @return 是否已存在
	 */
	private static boolean isDuplicationInNewTable(String sqlFingerprint) {
		try {
			JdbcTemplate template = getJdbcTemplate();
			if (template == null) {
				log.error("无法获取JdbcTemplate");
				return false;
			}

			// 查询新表中是否存在相同的SQL指纹
			String sql = "SELECT COUNT(*) FROM blade_slow_sql_alert WHERE sql_statement = ?";
			Integer count = template.queryForObject(sql, Integer.class, sqlFingerprint);
			return count != null && count > 0;

		} catch (DataAccessException e) {
			log.debug("查询新表SQL指纹异常，回退到旧表查询: {}", e.getMessage());
			// 如果新表查询失败，回退到旧表查询
			return isDuplication(sqlFingerprint);
		}
	}

	/**
	 * 提取纯净的API路径
	 * 处理各种可能的格式，确保只返回URL路径部分
	 *
	 * @param apiPath 原始API路径字符串
	 * @return 纯净的URL路径
	 */
	private static String extractCleanApiPath(String apiPath) {
		if (apiPath == null || apiPath.trim().isEmpty()) {
			return "未知路径";
		}

		String cleanPath = apiPath.trim();

		// 处理包含"接口路径: "前缀的情况
		if (cleanPath.startsWith("接口路径: ")) {
			cleanPath = cleanPath.substring("接口路径: ".length());
		}

		// 处理包含换行符的情况，只保留第一行
		if (cleanPath.contains("\n")) {
			cleanPath = cleanPath.split("\n")[0].trim();
		}

		// 处理包含回车符的情况
		if (cleanPath.contains("\r")) {
			cleanPath = cleanPath.split("\r")[0].trim();
		}

		// 处理可能包含其他分隔符的情况（如制表符、多个空格等）
		cleanPath = cleanPath.replaceAll("\\s+", " ").trim();

		// 验证是否为有效的URL路径格式
		if (cleanPath.isEmpty()) {
			return "未知路径";
		}

		// 如果不是以/开头的路径，但包含常见的路径字符，尝试提取
		if (!cleanPath.startsWith("/") && cleanPath.contains("/")) {
			// 处理完整URL的情况（如 http://localhost:8080/api/test）
			if (cleanPath.startsWith("http://") || cleanPath.startsWith("https://")) {
				// 查找第三个/开始的部分（协议://域名/路径）
				int protocolEnd = cleanPath.indexOf("://");
				if (protocolEnd >= 0) {
					int pathStart = cleanPath.indexOf("/", protocolEnd + 3);
					if (pathStart >= 0) {
						cleanPath = cleanPath.substring(pathStart);
					}
				}
			} else {
				// 查找第一个/开始的部分
				int slashIndex = cleanPath.indexOf("/");
				if (slashIndex >= 0) {
					cleanPath = cleanPath.substring(slashIndex);
				}
			}
		}

		// 移除可能的查询参数和片段标识符（保持路径的纯净性）
		if (cleanPath.contains("?")) {
			cleanPath = cleanPath.split("\\?")[0];
		}
		if (cleanPath.contains("#")) {
			cleanPath = cleanPath.split("#")[0];
		}

		// 最终验证和清理
		cleanPath = cleanPath.trim();
		if (cleanPath.isEmpty() || cleanPath.equals("/")) {
			return cleanPath.isEmpty() ? "未知路径" : "/";
		}

		log.debug("API路径清理: 原始='{}' -> 清理后='{}'", apiPath, cleanPath);

		return cleanPath;
	}

	/**
	 * 生成SQL指纹（去除参数值的SQL模板）
	 *
	 * @param sql 原始SQL
	 * @return SQL指纹
	 */
	private static String getSqlFingerprint(String sql) {
		if (sql == null || sql.trim().isEmpty()) {
			return "";
		}

		// 简单的SQL指纹生成：将参数值替换为占位符
		return sql.replaceAll("'[^']*'", "?")  // 替换字符串参数
			.replaceAll("\\b\\d+\\b", "?")  // 替换数字参数
			.replaceAll("\\s+", " ")        // 标准化空格
			.trim();
	}

	/**
	 * 获取所有SQL指纹列表（用于批量检查 - 使用JdbcTemplate）
	 *
	 * @return SQL指纹列表
	 */
	public static List<String> getAllSqlFingerprints() {
		try {
			JdbcTemplate template = getJdbcTemplate();
			if (template == null) {
				log.error("无法获取JdbcTemplate");
				return new ArrayList<>();
			}

			String sql = "SELECT ip FROM filter_log";
			return template.queryForList(sql, String.class);

		} catch (DataAccessException e) {
			log.error("查询所有SQL指纹异常", e);
			return new ArrayList<>();
		}
	}

	/**
	 * 批量检查SQL指纹是否存在（使用JdbcTemplate）
	 *
	 * @param sqlFingerprints SQL指纹列表
	 * @return 存在的SQL指纹列表
	 */
	public static List<String> batchCheckDuplication(List<String> sqlFingerprints) {
		if (sqlFingerprints == null || sqlFingerprints.isEmpty()) {
			return new ArrayList<>();
		}

		try {
			JdbcTemplate template = getJdbcTemplate();
			if (template == null) {
				log.error("无法获取JdbcTemplate");
				return new ArrayList<>();
			}

			// 构建IN查询
			StringBuilder sqlBuilder = new StringBuilder("SELECT ip FROM filter_log WHERE ip IN (");
			for (int i = 0; i < sqlFingerprints.size(); i++) {
				if (i > 0) sqlBuilder.append(",");
				sqlBuilder.append("?");
			}
			sqlBuilder.append(")");

			return template.queryForList(sqlBuilder.toString(), String.class, sqlFingerprints.toArray());

		} catch (DataAccessException e) {
			log.error("批量查询SQL指纹异常", e);
			return new ArrayList<>();
		}
	}

	/**
	 * 获取数据源状态信息
	 *
	 * @return 数据源状态信息
	 */
	public static String getDataSourceStatus() {
		if (dataSource == null) {
			return "数据源未初始化";
		}

		try {
			return String.format("数据源状态 - 活跃连接: %d, 最大连接: %d, URL: %s",
				dataSource.getActiveCount(),
				dataSource.getMaxActive(),
				maskUrl(dataSource.getUrl()));
		} catch (Exception e) {
			return "获取数据源状态失败: " + e.getMessage();
		}
	}

	/**
	 * 测试数据库连接
	 *
	 * @return 连接是否成功
	 */
	public static boolean testConnection() {
		try {
			JdbcTemplate template = getJdbcTemplate();
			if (template == null) {
				return false;
			}

			template.queryForObject("SELECT 1", Integer.class);
			log.info("慢SQL数据库连接测试成功");
			return true;

		} catch (DataAccessException e) {
			log.error("慢SQL数据库连接测试失败", e);
			return false;
		}
	}
}
